﻿// <copyright file="MapTo.cs" company="DataAbstractor">
//   (c) Luke Geraghty 2013
// </copyright>
// <summary>
//   Mapping for the source class property.
// </summary>

namespace DataAbstractor
{
    using System;
    using System.Globalization;
    using System.Linq;
    using System.Linq.Expressions;

    /// <summary>
    /// Mapping for the source class property.
    /// </summary>
    /// <typeparam name="TDestination">The destination type.</typeparam>
    /// <typeparam name="TSource">The source type.</typeparam>
    internal class MapTo<TDestination, TSource> : IMapTo<TDestination, TSource>
    {
        /// <summary>
        /// The mapping.
        /// </summary>
        private readonly MapEntry mapping;

        /// <summary>
        /// The destination field name.
        /// </summary>
        private readonly string destinationClassPropertyName;

        /// <summary>
        /// Initializes a new instance of the <see cref="MapTo{TDestination,TSource}"/> class.
        /// </summary>
        /// <param name="mapping">
        /// The mapping.
        /// </param>
        /// <param name="destinationClassPropertyName">
        /// The destination class property name.
        /// </param>
        public MapTo(MapEntry mapping, string destinationClassPropertyName)
        {
            this.mapping = mapping;
            this.destinationClassPropertyName = destinationClassPropertyName;
        }

        /// <summary>
        /// Map the destination property to a value.
        /// </summary>
        /// <param name="value">The value to map the property to.</param>
        /// <returns>The destination mapping class.</returns>
        public IMapFrom<TDestination, TSource> Value(object value)
        {
            this.mapping.SetMap(this.destinationClassPropertyName, new MapEntry.MapValue { Value = value });
            return new MapFrom<TDestination, TSource>(this.mapping);
        }

        /// <summary>
        /// Map the destination property to a value in the source class.
        /// </summary>
        /// <param name="source">The source property.</param>
        /// <returns>The destination mapping class.</returns>
        public IMapFrom<TDestination, TSource> To(Expression<Func<TSource, object>> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            var name = ExpressionHelper.GetPropertyName(source);
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException("Unable to get member name from source");
            }

            var sourceProperty = typeof(TSource).GetProperties().FirstOrDefault(i => i.Name == name && i.CanRead);
            if (sourceProperty == null)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unable to locate the field {0} in source class", name));
            }

            this.mapping.SetMap(this.destinationClassPropertyName, new MapEntry.MapValue { ToClassMember = sourceProperty });
            return new MapFrom<TDestination, TSource>(this.mapping);
        }
    }
}
